﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace SpriteMaker
{
    public partial class OneClickDatagrid : DataGridView
    {
        private List<DataGridViewColumn> singleClickColumns = new List<DataGridViewColumn>();
        public OneClickDatagrid()
        {
            InitializeComponent();
        }
        public void DefineSingleClickColumns(List<DataGridViewColumn> columns)
        {
            singleClickColumns.Clear();

            foreach (DataGridViewColumn column in columns)
            {
                if (this.Columns.IndexOf(column) == -1)
                {
                    throw new ArgumentException("Instance of column (" + column.Name + ") is not in this DataGridView");
                }
                singleClickColumns.Add(column);
            }
        }
        public void DefineSingleClickColumns(List<int> columnIndexes)
        {
            singleClickColumns.Clear();
            foreach (int columnIndex in columnIndexes)
            {
                if (columnIndex < 0 || columnIndex >= this.ColumnCount)
                {
                    throw new ArgumentOutOfRangeException("Column index (" + columnIndex + ") is out of range");
                }
                singleClickColumns.Add(this.Columns[columnIndex]);
            }
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            //If primary mouse button not down, do standard processing
            if (e.Button != MouseButtons.Left)
            {
                base.OnMouseDown(e);
                return;
            }
            //Get info on where user clicked
            DataGridView.HitTestInfo hitInfo = HitTest(e.X, e.Y);

            //If a cell wasn't clicked, column isn't text or it's read only, do standard processing
            if (hitInfo.Type != DataGridViewHitTestType.Cell || !(this.Columns[hitInfo.ColumnIndex].GetType() == typeof(DataGridViewTextBoxColumn))
                || this.Columns[hitInfo.ColumnIndex].ReadOnly)
            {
                base.OnMouseDown(e);
                return;
            }

            //If functionality enabled for specific columns and column clicked is not one of these, do standard processing
            if (singleClickColumns.Count >= 1 && singleClickColumns.IndexOf(this.Columns[hitInfo.ColumnIndex]) == -1)
            {
                base.OnMouseDown(e);
                return;
            }

            //Get clicked cell
            DataGridViewCell clickedCell = this.Rows[hitInfo.RowIndex].Cells[hitInfo.ColumnIndex];

            //If cell not current, try and make it so
            if (CurrentCell != clickedCell)
            {
                this.EndEdit();
                //Allow standard processing make clicked cell current
                base.OnMouseDown(e);

                //If this didn't happen (validation failed etc), abort
                if (this.CurrentCell != clickedCell)
                {
                    return;
                }
            }


            //If already in edit mode, do standard processing (will position caret)
            if (this.CurrentCell.IsInEditMode)
            {
                base.OnMouseDown(e);
                return;
            }

            //Enter edit mode
            this.BeginEdit(false);

            //Ensure text is scrolled to the left
            TextBoxBase textBox = (TextBoxBase)this.EditingControl;

            textBox.SelectionStart = 0;

            textBox.ScrollToCaret();

            //Position caret by simulating a mouse click within control
            int editOffset = e.X - hitInfo.ColumnX - this.EditingControl.Left;

            Int32 lParam = MakeLong(editOffset, 0);

            SendMessage(this.EditingControl.Handle, WM_LBUTTONDOWN, 0, lParam);

            SendMessage(this.EditingControl.Handle, WM_LBUTTONUP, 0, lParam);
        }
        protected override bool ProcessDialogKey(Keys keyData)
        {
            if (keyData == Keys.Enter)
            {
                this.EndEdit();
                int col = this.CurrentCell.ColumnIndex;
                int row = this.CurrentCell.RowIndex;
                this.CurrentCell = this[col, row];
                return true;
            }
            return base.ProcessDialogKey(keyData);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.KeyData == Keys.Enter)
            {
                this.EndEdit();
                int col = this.CurrentCell.ColumnIndex;
                int row = this.CurrentCell.RowIndex;
                this.CurrentCell = this[col, row];
                e.Handled = true;
            }
            base.OnKeyDown(e);
        }
        const int WM_LBUTTONDOWN = 513;

        const int WM_LBUTTONUP = 514;

        [DllImport("user32.dll")]
        private static extern bool SendMessage(IntPtr hWnd, Int32 msg, Int32 wParam, Int32 lParam);



        private int MakeLong(int loWord, int hiWord)
        {
            return (hiWord << 16) | (loWord & 65535);
        }
        protected void BaseOnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
        }

    }
}
